/*****************************************************************************
 *                                                                           *
 * Module:       SRAM_Controller                                             *
 * Description:                                                              *
 *      This module is used for the sram controller for part II of the bus   *
 *   communication exercise in Altera's computer organization lab set.       *
 *                                                                           *
 * This module is a skeleton and must be completed as part of this exercise. *
 *                                                                           *
 *****************************************************************************/

module SRAM_Controller (
	// Inputs
	clk,
	reset_n,
	
	address,
	bus_enable,
	byte_enable,
	rw,
	write_data,
	
	// Bidirectionals
	SRAM_DQ,
	
	// Outputs
	acknowledge,
	read_data,
	
	register_0,
	register_1,
	register_2,
	register_3,
	
	SRAM_ADDR,

	SRAM_CE_N,
	SRAM_WE_N,
	SRAM_OE_N,
	SRAM_UB_N,
	SRAM_LB_N
);

/*****************************************************************************
 *                           Parameter Declarations                          *
 *****************************************************************************/


/*****************************************************************************
 *                             Port Declarations                             *
 *****************************************************************************/

// Inputs
input				clk;
input				reset_n;

input		[31:0]	address;
input				bus_enable;
input		[1:0]	byte_enable;
input				rw;
input		[15:0]	write_data;

// Bidirectionals
inout		[15:0]	SRAM_DQ;

// Outputs
output				acknowledge;
output		[15:0]	read_data;

output		[17:0]	SRAM_ADDR;

output				SRAM_CE_N;
output				SRAM_WE_N;
output				SRAM_OE_N;
output				SRAM_UB_N;
output				SRAM_LB_N;

output	reg	[15:0]	register_0;
output	reg	[15:0]	register_1;
output	reg	[15:0]	register_2;
output	reg	[15:0]	register_3;


/*****************************************************************************
 *                 Internal Wires and Registers Declarations                 *
 *****************************************************************************/

// Internal Wires

	wire [1:0]regIndex;
	assign regIndex = address[18:17];
	
wire isRAM;
assign isRAM = (!address[19])&(bus_enable);

// Internal Registers

// State Machine Registers

	reg [1:0] current, next;
	parameter [1:0] A=0, B=1, C=2, D=3;
	
/*****************************************************************************
 *                         Finite State Machine(s)                           *
 *****************************************************************************/
	always @(current) begin
		case(current)
		A: 
		begin
		if(bus_enable)
			if(rw)
			begin
			//read
				next=C;
			end
			else
			begin
			//write
				next=B;

			end
		else
			next=A;
		end
		
		B: next=D;
		
		C: next=D;
		
		D: next=A;

		default: next=A;
		endcase
	end

/*****************************************************************************
 *                             Sequential Logic                              *
 *****************************************************************************/


/*****************************************************************************
 *                            Combinational Logic                            *
 *****************************************************************************/

assign acknowledge	= (current==D);

wire [15:0] readTmp;
assign readTmp = regIndex[1]?(regIndex[0]? register_3:register_2):(regIndex[1]? register_1:register_0);

assign read_data	= isRAM? (readTmp):(rw? SRAM_DQ:16'hx);//read

assign SRAM_DQ		= rw? 16'hz:write_data;//write

assign SRAM_ADDR	= address[17:0];

assign SRAM_CE_N	= (current==B)|(current==C);
assign SRAM_WE_N	= !rw;
assign SRAM_OE_N	= rw;
assign SRAM_UB_N	= /* Add/Edit code here */ 1'b1;
assign SRAM_LB_N	= /* Add/Edit code here */ 1'b1;

/*****************************************************************************
 *                              Internal Modules                             *
 *****************************************************************************/
always @(posedge clk)
begin
	current <= next;
	
	case(current)
	B:
	begin
	if(!isRAM)
	begin
		case(regIndex)
			0:register_0<=write_data;
			1:register_1<=write_data;
			2:register_2<=write_data;
			3:register_3<=write_data;
		endcase
	end
	end
	/*
	C:
	begin
		case(regIndex)
			0:curData<=register_0;
			1:curData<=register_1;
			2:curData<=register_2;
			3:curData<=register_3;
		endcase	
	end
	*/
	endcase
	
	if (reset_n == 0)
	begin
		register_0 <= 16'h0000;
		register_1 <= 16'h0000;
		register_2 <= 16'h0000;
		register_3 <= 16'h0000;
	end
end

endmodule

